Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

34장. 의존성은 왜 문제가 되는가

33장에서 우리는
레이어 아키텍처의 구조를 보았다.

  • Controller → Service → Repository
  • 위에서 아래로 의존하는 구조

이 구조는 단순하고 이해하기 쉽다.

하지만 시스템이 커질수록
문제가 발생한다.


의존성이란 무엇인가

의존성이란
한 코드가 다른 코드를 알고 사용하는 관계다.

예를 들어:

class OrderService {
    private OrderRepository repository = new MySQLOrderRepository();
}

이 경우:

OrderService는 MySQLOrderRepository에 의존한다


문제는 의존성 자체가 아니다

의존성은 나쁜 것이 아니다.

문제는 이것이다.

무엇이 무엇에 의존하는가


변하는 것과 변하지 않는 것

시스템에는 두 가지 종류가 있다.


변하는 것

  • DB (MySQL → DynamoDB)
  • 메시지 브로커 (Kafka → SQS)
  • 외부 API
  • 캐시, 인프라 기술

이들은 상황에 따라
언제든 바뀔 수 있다.


변하지 않아야 하는 것

  • 주문 생성 로직
  • 결제 처리 규칙
  • 상태 전이 규칙

이것은
서비스의 핵심 비즈니스 로직이다.


우리가 원하는 상태

자연스럽게 이렇게 생각할 수 있다.

변하지 않아야 하는 것은
변하는 것에 영향을 받으면 안 된다


하지만 현재 구조는 반대다

레이어 구조를 다시 보자.

Service → DB
Service → Kafka
Service → External API

이 구조의 의미는 이것이다.

비즈니스 로직이 외부 기술에 의존한다


왜 이것이 문제인가

이 상태에서는
변경이 발생할 때마다 문제가 생긴다.


1️⃣ 기술 변경이 로직을 흔든다

  • DB 변경
  • 메시지 시스템 변경

→ Service 코드 수정 필요


2️⃣ 테스트가 어려워진다

Service를 테스트하려면

  • DB가 필요하고
  • Kafka가 필요하다

→ 빠른 테스트 불가능


3️⃣ 코드가 점점 복잡해진다

Service
 ├─ DB 처리
 ├─ Kafka 발행
 ├─ 외부 API 호출
 ├─ 비즈니스 로직

→ 핵심 로직이 흐려진다


문제의 본질

핵심은 이것이다.

변하지 않아야 하는 것이
변하는 것에 의존하고 있다

이 구조에서는
시스템이 안정될 수 없다.


그래서 방향을 바꾼다

이 문제를 해결하려면
의존성 방향을 바꿔야 한다.


현재 구조

Service → DB

우리가 원하는 구조

DB → Service

즉,

외부 기술이 비즈니스 로직에 의존해야 한다


이게 가능한가?

여기서 자연스럽게 질문이 나온다.

DB가 Service를 어떻게 의존하지?

이 질문을 해결하는 것이
다음 개념들이다.


인터페이스

먼저, 역할을 정의한다.

interface OrderRepository {
    void save(Order order);
}

Service는 이렇게 바뀐다.

class OrderService {
    private final OrderRepository repository;

    public OrderService(OrderRepository repository) {
        this.repository = repository;
    }
}

이제 Service는

구현체가 아니라 “역할”에 의존한다


중요한 변화

이 구조에서 핵심은 이것이다.

Service는 어떤 DB를 쓰는지 모른다


제어 역전 (Inversion of Control)

이제 객체를 누가 만들까?

기존:

Service가 직접 생성

변경 후:

외부에서 만들어서 넣어준다

이것을

제어 역전 (IoC)

이라고 한다.


의존성 주입 (Dependency Injection)

실제 연결은 이렇게 이루어진다.

OrderRepository repo = new MySQLOrderRepository();
OrderService service = new OrderService(repo);

이것을

의존성 주입 (DI)

이라고 한다.


결과적으로 바뀌는 것

Before

Service → MySQLRepository

After

Service → Repository Interface
Repository 구현체 → Service에 주입

이 변화의 의미

이 변화는 단순한 코드 스타일이 아니다.


1️⃣ 비즈니스 로직이 보호된다

Service는 더 이상

  • DB
  • Kafka
  • 외부 API

를 알지 않는다


2️⃣ 기술 변경이 쉬워진다

  • MySQL → DynamoDB 변경

→ Service 수정 없음


3️⃣ 테스트가 쉬워진다

OrderRepository fake = new FakeRepository();
OrderService service = new OrderService(fake);

→ 외부 의존 없이 테스트 가능


이벤트 기반 시스템에서의 의미

이벤트 기반 구조에서는
외부 의존성이 더 많다.

  • 메시지 브로커
  • Outbox
  • Inbox
  • 외부 API

이 상태에서 의존성 방향이 잘못되면

시스템은 빠르게 복잡해진다


이제 다음 단계

지금까지 우리는

  • 의존성의 문제를 이해했고
  • 방향을 왜 바꿔야 하는지 보았고
  • 그 방법을 배웠다

이제 남은 질문은 이것이다.

이 구조를 시스템 전체에 적용하면 어떻게 될까?

그 답이

헥사고날 아키텍처

다.


이 장의 핵심

  • 의존성 자체는 문제가 아니다
  • 문제는 “의존성의 방향”이다
  • 변하지 않아야 하는 것은 보호되어야 한다
  • 외부 기술은 언제든 바뀔 수 있다
  • 의존성 방향을 뒤집어야 구조가 안정된다
  • 인터페이스, IoC, DI가 이를 가능하게 한다